#pragma once

#include "Log.hpp"
#include "Thread.hpp"
#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

struct SendMessageData
{
    int _sock;
    struct sockaddr_in _sock_srv;
    socklen_t _len;

    SendMessageData(int sock, struct sockaddr_in sock_srv)
        : _sock(sock), _sock_srv(sock_srv), _len(sizeof(sock_srv))
    {
    }
};

class Client
{
public:
    // 构造函数
    Client(const std::string &ip, uint16_t port)
        : _ip(ip), _port(port), _sock(-1)
    {
    }

    // 初始化函数
    void init()
    {
        // 1. 创建网络套接字
        _sock = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sock < 0)
        {
            logMessage(FATAL, "%d:%s", errno, strerror(errno));
            exit(2);
        }

        // 2. 绑定 -- 客户端需要绑定，但一般不会由程序员来进行绑定
        // 而是在第一次发送消息时，由OS自动分配ip和port
    }

    // 客户端启动程序
    void start()
    {
        // 创建服务器的struct sockaddr
        struct sockaddr_in srv_sock;
        memset(&srv_sock, 0, sizeof(srv_sock));
        srv_sock.sin_family = AF_INET;
        srv_sock.sin_addr.s_addr = inet_addr(_ip.c_str()); // 主机ip转为网络ip
        srv_sock.sin_port = htons(_port);                  // 主机port转为网络port

        SendMessageData sendData(_sock, srv_sock);

        // 发送消息
        thread th_send(send_message, (void *)&sendData);
        th_send.start();

        // 接受反馈回来的消息
        thread th_recieve(recieve_message, (void *)&_sock);
        th_recieve.start();

        // std::string msg;
        // std::cout << "请输入你要发送的消息: " << std::flush;
        // std::getline(std::cin, msg); // 按行读取
        // sendto(_sock, msg.c_str(), msg.size(), 0, (const sockaddr *)&srv_sock, sizeof(srv_sock));

        th_send.join();
        th_recieve.join();

        // struct sockaddr tmp;
        // socklen_t len = sizeof(tmp);
        // char buffer[1024];
        // memset(buffer, 0, sizeof(buffer));
        // if (recvfrom(_sock, (void *)buffer, sizeof(buffer) - 1, 0, (sockaddr *)&tmp, &len) < 0)
        // {
        //     logMessage(ERROR, "读取服务器消息失败, %d:%s\n", errno, strerror(errno));
        //     continue;
        // }
        // printf("Serve# %s\n", buffer);
    }

    // 析构函数
    ~Client()
    {
        if (_sock < 0)
        {
            close(_sock);
        }
    }

private:
    static void *send_message(void *args)
    {
        SendMessageData *ptr = (SendMessageData *)args;
        while (true)
        {
            std::string msg;
            std::cerr << "请输入你要发送的消息: " << std::flush;
            std::getline(std::cin, msg); // 按行读取
            sendto(ptr->_sock, msg.c_str(), msg.size(), 0, (const sockaddr *)&ptr->_sock_srv, ptr->_len);
        }
        return nullptr;
    }

    static void *recieve_message(void *args)
    {
        // memset(buffer, 0, sizeof(buffer));
        char buffer[1024];
        while (true)
        {
            struct sockaddr tmp;
            memset(&tmp, 0, sizeof(tmp));
            socklen_t len = sizeof(tmp);

            ssize_t n = recvfrom(*(int *)args, (void *)buffer, sizeof(buffer) - 1, 0, (sockaddr *)&tmp, &len);
            // logMessage(NORMAL, "读取到了服务器数据!\n");
            // buffer[n] = '\0';
            // printf("%s\n", buffer);
            
            if (n > 0)
            {
                // std::cerr << "aaaa" << std::endl;
                buffer[n] = '\0';
                printf("%s\n", buffer);
            }
        }
        return nullptr;
    }

    std::string _ip; // 发生数据的主机ip
    uint16_t _port;  // 端口号
    int _sock;       // 套接字
};